
package common;


/**
 * Holds a reference to an instance that must be shared between two threads, one
 * producer and one consumer. The producer sets the data and the consumer gets it.
 * Only the lastly set data is kept here, they are not enqueued. This is intended
 * to be used with data which has time coherence and only the most recent data
 * matters. It is intended to be used in passing data from the physics thread
 * (object positions) to the rendering thread then only the most recent data matters.
 * Also, for passing data from the physics thread to the update thread in the
 * game server.
 *
 * @author xissburg
 */
public class SharedBuffer <T>
{
    private T data;
    private volatile boolean hasNewData;

    public SharedBuffer() {
        data = null;
        hasNewData = false;
    }

    /**
     * Sets the data field to point to the same instance as the data paramater.
     * The next call to get() will return this same instance.
     *
     * @param data Instance to be shared.
     */
    public synchronized void set(T data)
    {
        assert(data != null);
        this.data = data;
        hasNewData = true;
        notify();
    }

    /**
     * If new data was set after the last get() of after instantiation of this
     * SharedBuffer it returns the lastly set data. Otherwise there is not new
     * data and, if wait is true the calling thread will sleep until new data is
     * set, else if wait is false it will immediately return null.
     *
     * @param wait Whether block until new data arrives or to return null
     * immediatelly if there's no new data at the moment of the call
     * @return The current data.
     * @throws InterruptedException If the current thread is interrupeted while
     * this method is blocked wating for new data. Hence, if wait is false, this
     * exception will never be thrown
     */
    public synchronized T get(boolean wait) throws InterruptedException
    {
        if(hasNewData)
        {
            hasNewData = false;
            return data;
        }
        else
        {
            if(wait)
            {
                while(hasNewData == false)
                    wait();

                hasNewData = false;
                return data;
            }
            else
                return null;
        }
    }
}
